﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace IEMSOFT.Foundation.Log
{
    public class SqlLogger : ILogger
    {
        public enum LogLevel
        {
            Debug = 1,
            Info = 2,
            Warn = 3,
            Error = 4,
            Fatal = 5
        }
        private PetaPoco.Database DbPovider { get { return new PetaPoco.Database(DbConStr); } }
        private string _dbConStr = string.Empty;
        private LogLevel ConfigLogLevel
        {
            get
            {
                var strLevel = string.Empty;
#if DEBUG
                  strLevel = Utility.GetAppSetting<string>("debug", "SqlLogLevel");
#else
                strLevel = Utility.GetAppSetting<string>("info", "SqlLogLevel");
#endif
                var logLevel = strLevel.ToEnum<LogLevel>();
                return logLevel;
            }
        }

        public string DbConStr
        {
            get
            {
                if (string.IsNullOrEmpty(_dbConStr))
                {
                    return Utility.GetAppSetting<string>("LoggingDB", "LoggingDB");
                }
                else
                {
                    return _dbConStr;
                }
            }
            set
            {
                _dbConStr = value;
            }
        }

        private string _logTableName = string.Empty;
        public string LogTableName
        {
            get
            {
                if (string.IsNullOrEmpty(_logTableName))
                {
                    return Utility.GetAppSetting<string>("SqlLogTable", "SqlLogTableName");
                }
                else
                {
                    return _logTableName;
                }
            }
            set
            {
                _logTableName = value;
            }
        }

        private string _loggerName = string.Empty;
        public string LoggerName
        {
            get
            {
                if (string.IsNullOrEmpty(_loggerName))
                {
                    return "DefaultLogger";
                }
                else
                {
                    return _loggerName;
                }
            }
            set
            {
                _loggerName = value;
            }
        }

        public SqlLogger(string logTableName, string dbConStr, string loggerName)
        {
            _logTableName = logTableName;
            _dbConStr = dbConStr;
            _loggerName = loggerName;
        }

        public SqlLogger(string logTableName, string loggerName):this(logTableName,null,loggerName)
        {
        }

        public SqlLogger(string loggerName)
            : this(null, null, loggerName)
        {
        }


        public SqlLogger()
            : this(null, null, null)
        {
        }

        public bool IsDebugEnabled
        {
            get { return LogLevel.Debug.ToInt()>= ConfigLogLevel.ToInt(); }
        }

        public bool IsErrorEnabled
        {
            get { return LogLevel.Error.ToInt() >= ConfigLogLevel.ToInt(); }
        }

        public bool IsFatalEnabled
        {
            get { return LogLevel.Fatal.ToInt() >= ConfigLogLevel.ToInt(); }
        }

        public bool IsInfoEnabled
        {
            get { return LogLevel.Info.ToInt() >= ConfigLogLevel.ToInt(); }
        }

        public bool IsWarnEnabled
        {
            get { return LogLevel.Warn.ToInt() >= ConfigLogLevel.ToInt(); }
        }

        public void Debug(object message)
        {
            try
            {
                Log(LogLevel.Error, message, null);
            }
            catch (Exception)
            {
#if DEBUG
                throw;
#endif
            }
        }

        public void Debug(object message, Exception exception)
        {
            try
            {
                var err = exception == null ? string.Empty : string.Format("{0}", exception);
                Log(LogLevel.Debug, message, err);
            }
            catch (Exception)
            {
#if DEBUG
                throw;
#endif
            }
        }

        public void Error(object message)
        {
            try
            {
                Log(LogLevel.Error, message, null);
            }
            catch (Exception)
            {
#if DEBUG
                throw;
#endif
            }

        }

        public void Error(object message, Exception exception)
        {
            try
            {
                var err = exception == null ? string.Empty : string.Format("{0}", exception);
                Log(LogLevel.Error, message, err);
            }
            catch (Exception)
            {
#if DEBUG
                throw;
#endif
            }

        }

        public void Fatal(object message)
        {
            try
            {
                Log(LogLevel.Fatal, message,null);
            }
            catch (Exception)
            {
#if DEBUG
                throw;
#endif
            }
        }

        public void Fatal(object message, Exception exception)
        {
            try
            {
                var err = exception == null ? string.Empty : string.Format("{0}", exception);
                Log(LogLevel.Fatal, message, err);
            }
            catch (Exception)
            {
#if DEBUG
                throw;
#endif
            }
        }

        public void Info(object message)
        {
            try
            {
                Log(LogLevel.Info, message, null);
            }
            catch (Exception)
            {
#if DEBUG
                throw;
#endif
            }
        }

        public void Info(object message, Exception exception)
        {
            try
            {
                var err = exception == null ? string.Empty : string.Format("{0}", exception);
                Log(LogLevel.Info, message, err);
            }
            catch (Exception)
            {
#if DEBUG
                throw;
#endif
            }
        }

        public void Warn(object message)
        {
            try
            {
                Log(LogLevel.Warn, message, null);
            }
            catch (Exception)
            {
#if DEBUG
                throw;
#endif
            }
        }

        public void Warn(object message, Exception exception)
        {
            try
            {
                var err = exception == null ? string.Empty : string.Format("{0}", exception);
                Log(LogLevel.Warn, message, err);
            }
            catch (Exception)
            {
#if DEBUG
                throw;
#endif
            }
        }

        public void Log(LogLevel level, object message, object exception)
        {
            try
            {
                //read SqlLogLevel configuration from appsetting,then check whether should populate into db
                if (level.ToInt() >= ConfigLogLevel.ToInt())
                {
                    var requestId = LogHelper.RequestVariables.GetCurrentRequestId();
                    var requestUrl = LogHelper.RequestVariables[LogRequestVariableType.RequestUrl];
                    var userId=LogHelper.RequestVariables[LogRequestVariableType.UserId];
                    var clientDeviceId = LogHelper.RequestVariables[LogRequestVariableType.ClientDeviceId];
                    var clientIP = LogHelper.RequestVariables[LogRequestVariableType.ClientIP];
                    var request = LogHelper.RequestVariables[LogRequestVariableType.Request];
                    var response = LogHelper.RequestVariables[LogRequestVariableType.Response];
                    var requestBeginTime = LogHelper.RequestVariables[LogRequestVariableType.RequestBeginTime];
                    var requestEndTime = LogHelper.RequestVariables[LogRequestVariableType.RequestEndTime];
                    var userAgent = LogHelper.RequestVariables[LogRequestVariableType.UserAgent];
                    var elapsed = string.Empty;
                    var requestBeginTimeStr = string.Empty;
                    var requestEndTimeStr = string.Empty;
                    if (requestBeginTime != null)
                    {
                        var beginTime = Convert.ToDateTime(requestBeginTime);
                        requestBeginTimeStr = beginTime.ToString("yyyy-MM-dd HH:mm:ss.fffffff");
                    }
                    if (requestEndTime != null)
                    {
                        var endTime = Convert.ToDateTime(requestEndTime);
                        requestEndTimeStr = endTime.ToString("yyyy-MM-dd HH:mm:ss.fffffff");
                    }

                    if (requestBeginTime != null && requestEndTime != null)
                    {
                        var beginTime = Convert.ToDateTime(requestBeginTime);
                        var endTime = Convert.ToDateTime(requestEndTime);
                        elapsed = (endTime - beginTime).TotalMilliseconds.ToString("f4");
                    }
                    if (elapsed == "") elapsed = null;

                    var sql = new StringBuilder();
                    sql.AppendFormat("Insert into {0} ", LogTableName);
                    sql.Append("(");
                    sql.Append("RequestId,");
                    sql.Append("RequestUrl,");
                    sql.Append("ClientDeviceId,");
                    sql.Append("ClientIP,");
                    sql.Append("RequestBeginTime,");
                    sql.Append("RequestEndTime,");
                    sql.Append("Elapsed,");
                    sql.Append("LogLevel,");
                    sql.Append("LoggerName,");
                    sql.Append("Message,");
                    sql.Append("Exeption,");
                    sql.Append("Request,");
                    sql.Append("Response,");
                    sql.Append("UserAgent,");
                    sql.Append("UserId,");
                    sql.Append("Created)");
                    sql.Append("Values(@0,@1,@2,@3,@4,@5,@6,@7,@8,@9,@10,@11,@12,@13,@14,@15)");
                    using (DbPovider)
                    {
                        DbPovider.Execute(sql.ToString(),
                                        requestId, requestUrl, clientDeviceId, clientIP, requestBeginTimeStr, requestEndTimeStr,
                                        elapsed, level.ToString(), LoggerName, message, exception, request, response,userAgent,userId,DateTime.Now);
                    }
                }
            }
            catch (Exception)
            {
#if DEBUG
                throw;
#endif
            }
        }
    }
}
